/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package station3d;

import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.event.*;
import java.util.Map;

/**
 * Správce vstupů.
 * @author Martin
 */
public class InputManager implements KeyListener, MouseListener, MouseMotionListener, MouseWheelListener {


    private int mouseX;
    private int mouseY;

    private InputState mouseButtonLeftSto = null;
    private InputState mouseButtonRightSto = null;
    private InputState mouseButtonMiddleSto = null;

    private InputState mouseWheelUpSto = null;
    private InputState mouseWheelDownSto = null;

    private Map<Integer, InputState> keyboardStos = new java.util.HashMap<Integer, InputState>();


    private int viewportWidth;
    private int viewportHeight;


    /** Vrátí x-ovou souřadnici myši. */
    public synchronized int getMouseX() {
        return this.mouseX;
    }

    /** Vrátí y-ovou souřadnici myši. */
    public synchronized int getMouseY() {
        return this.mouseY;
    }

    /** Nastaví stavový objekt pro levé tlačítko myši. */
    public void setMouseButtonLeftStateObject(InputState sto) {
        mouseButtonLeftSto = sto;
    }

    /** Nastaví stavový objekt pro pravé tlačítko myši. */
    public void setMouseButtonRightStateObject(InputState sto) {
        mouseButtonRightSto = sto;
    }

    /** Nastaví stavový objekt pro levé tlačítko myši. */
    public void setMouseButtonMiddleStateObject(InputState sto) {
        mouseButtonMiddleSto = sto;
    }

    /** Nastaví stavový objekt pro pohyb kolečkem myši nahoru. */
    public void setMouseWheelUpStateObject(InputState sto) {
        mouseWheelUpSto = sto;
    }

    /** Nastaví stavový objekt pro pohyb kolečkem myši dolů. */
    public void setMouseWheelDownStateObject(InputState sto) {
        mouseWheelDownSto = sto;
    }


    /** Nastaví stavový objekt pro zadanou klávesu. */
    public void setKeyboardStateObject(int keyCode, InputState sto) {
        keyboardStos.put(keyCode, sto);
    }


    /** Resetuje mapování stavových objektů na události. */
    public void reset() {
        mouseButtonLeftSto = null;
        mouseButtonMiddleSto = null;
        mouseButtonRightSto = null;
        mouseWheelDownSto = null;
        mouseWheelUpSto = null;
        keyboardStos.clear();
    }


    public synchronized int getViewportWidth() {
        return viewportWidth;
    }

    public synchronized int getViewportHeight() {
        return viewportHeight;
    }

    public synchronized void setViewportWidth(int viewportWidth) {
        this.viewportWidth = viewportWidth;
    }
    
    public synchronized void setViewportHeight(int viewportHeight) {
        this.viewportHeight = viewportHeight;
    }




    /** Stav klávesy (resp. tlačítka myši). */
    public static class InputState {

        /** Chování stavu události. */
        public static enum InputStateBehavior {
            /** Je vrácen skutečný stav stisku klávesy. */
            NORMAL,
            /** Stav 'true' je vrácen pouze při prvním dotaz. */
            CATCH_ONLY_ONCE
        };


        /** Stav. */
        private boolean state = false;

        /** Chování. */
        private InputStateBehavior behavior;

        /** Vytvoří objekt pro zjištění stavu klávesy se standardním chováním. */
        public InputState() {
            this(InputStateBehavior.NORMAL);
        }

        /** Vytvoří objekt pro zjištění stavu klávesy se zadaným chováním. */
        public InputState(InputStateBehavior behavior) {
            this.behavior = behavior;
        }

        /** Vrátí stav klávesy. */
        public boolean isPressed() {
            if (behavior == InputStateBehavior.CATCH_ONLY_ONCE) {
                if (state == true) {
                    state = false;
                    return true;
                }
                else return false;
            }
            else {
                return state;
            }
        }

        /** Stiskne klávesu. */
        private void press() {
            state = true;
        }

        /** Uvolní klávesu. */
        private void release() {
            state = false;
        }

    }


    @Override
    public synchronized void keyTyped(KeyEvent e) {

    }

    @Override
    public synchronized void keyPressed(KeyEvent e) {
        InputState sto = keyboardStos.get(e.getKeyCode());
        if (sto != null) {
            sto.press();
        }
    }

    @Override
    public synchronized void keyReleased(KeyEvent e) {
        InputState sto = keyboardStos.get(e.getKeyCode());
        if (sto != null) {
            sto.release();
        }
    }

    @Override
    public synchronized void mouseClicked(MouseEvent e) {

    }

    @Override
    public synchronized void mousePressed(MouseEvent e) {
        InputState sto = null;
        switch (e.getButton()) {
            case MouseEvent.BUTTON1: sto = mouseButtonLeftSto; break;
            case MouseEvent.BUTTON2: sto = mouseButtonMiddleSto; break;
            case MouseEvent.BUTTON3: sto = mouseButtonRightSto; break;
        }
        if (sto != null) {
            sto.press();
        }
    }

    @Override
    public synchronized void mouseReleased(MouseEvent e) {
        InputState sto = null;
        switch (e.getButton()) {
            case MouseEvent.BUTTON1: sto = mouseButtonLeftSto; break;
            case MouseEvent.BUTTON2: sto = mouseButtonMiddleSto; break;
            case MouseEvent.BUTTON3: sto = mouseButtonRightSto; break;
        }
        if (sto != null) {
            sto.release();
        }
    }

    @Override
    public synchronized void mouseEntered(MouseEvent e) {

    }

    @Override
    public synchronized void mouseExited(MouseEvent e) {

    }

    @Override
    public synchronized void mouseDragged(MouseEvent e) {
        this.mouseX = e.getX();
        this.mouseY = e.getY();
    }

    @Override
    public synchronized void mouseMoved(MouseEvent e) {
        this.mouseX = e.getX();
        this.mouseY = e.getY();
    }

    @Override
    public synchronized void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getWheelRotation() < 0) {
            if (mouseWheelUpSto != null) mouseWheelUpSto.press();
        }
        else {
            if (mouseWheelDownSto != null) mouseWheelDownSto.press();
        }
    }



}
